#ifndef COLA_H_
#define COLA_H_
#include <sys/types.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <string>
#include <sstream>
#include "QueueExceptions.h"
using namespace std;

template<class T> class Cola {
private:
	key_t clave;
	int id;

public:
	Cola(const std::string& archivo, const char letra);
	~Cola();
	void escribir(const T& dato) const;
	void leer(const int tipo, T* buffer) const;
	void destruir() const;
};

template<class T> Cola<T>::Cola(const std::string& archivo, const char letra) {
	clave = ftok(archivo.c_str(), letra);
	if (clave == -1)
		throw(CreateQueueException("Error en ftok"));

	id = msgget(clave, 0777 | IPC_CREAT);
	if (id == -1)
		throw(CreateQueueException("Error en msgget"));
}

template<class T> Cola<T>::~Cola() {
}

template<class T> void Cola<T>::destruir() const {
	int resultado = msgctl(id, IPC_RMID, NULL);
	if (resultado == -1)
		throw DestroyQueueException("Error en msgctl");
}

template<class T> void Cola<T>::escribir(const T& dato) const {
	int resultado = msgsnd(this->id, static_cast<const void*>(&dato),
			sizeof(T) - sizeof(long), 0);
	if (resultado == -1)
		throw(sendMsgException("Error en msgsnd"));
}

template<class T> void Cola<T>::leer(const int tipo, T* buffer) const {
	int size = sizeof(T) - sizeof(long);
	int resultado = msgrcv(this->id, static_cast<void *>(buffer), size, tipo, 0);

	if (resultado == -1)
		throw(rcvMsgException("Error en msgrcv"));
	else if (resultado < size) {
		// Se recibieron menos bytes de los esperados
		stringstream ss;
		ss << resultado;
		throw(incompleteRcvMsgException(ss.str()));
	}
}

#endif /* COLA_H_ */
